import 'dart:io';

import 'package:dartx/dartx.dart';
import 'package:dio/dio.dart';
import 'package:flutter/services.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:get/get.dart';
import 'package:nordic_dfu/nordic_dfu.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sgy_flutter/ble/HardwareVersion.dart';
import 'package:sgy_flutter/ble/errors.dart';
import 'package:sgy_flutter/extensions/get.dart';
import 'package:sgy_flutter/model/dfu_info_model.dart';
import 'package:sgy_flutter/extensions/device_model_firmware_check.dart';
import 'package:path/path.dart' as path;
import 'package:sgy_flutter/widget/app_dialog.dart';

import '../../ble/ble_manager.dart';

enum DfuPageState { normal, update, success, needCharging }

class DfuLogic extends GetxController {
  var loading = true.obs;
  Rx<DfuPageState> state = Rx(DfuPageState.normal);

  var progress = "".obs;
  var dfuTaskName = "".obs;
  var dfuTaskState = "".obs;

  Rxn<DfuInfoModel> dfuModel = Rxn();
  Rxn<DfuInfoModel> dfuModelRight = Rxn();

  Rxn<String> targetFirmwareVersion = Rxn();
  Rxn<String> targetFirmwareVersionRight = Rxn();
  Pair<String?, String?>? fallbackPair = null;
  Pair<String?, String?>? fallbackPairRight = null;

  bool get isDoubleSlide =>
      rightBleManager.deviceModel?.isDoubleSlide == true ||
      bleManager.deviceModel?.isDoubleSlide == true;

  // 0 OTA 1 fallback
  int otaOrFallback = 0;

  bool needAlertChargingAfterSuccess = false;

  @override
  void onReady() async {
    try {
      loading(true);
      final resp = await apiService.checkBlacklist(
          deviceName: bleManager.deviceModel?.name ?? "",
          deviceSN: bleManager.deviceModel?.deviceSN ?? '1');
      final isBlacklist = resp.data == true;
      if (!isBlacklist) {
        var resp = await bleManager.checkDfu();
        dfuModel(resp);
        if (bleManager.deviceModel?.isDoubleSlide == true ||
            rightBleManager.deviceModel?.isDoubleSlide == true) {
          var resp = await rightBleManager.checkDfu();
          dfuModelRight(resp);
        }
      }
    } catch (e) {
      printError(info: "$e");
    } finally {
      loading(false);
    }
    super.onReady();
  }

  @override
  void onClose() {
    if (state.value == DfuPageState.success){
      try {
        if (bleManager.deviceModel != null) {
          bleManager.connect(bleManager.deviceModel!);
        }
        if (rightBleManager.deviceModel != null) {
          rightBleManager.connect(rightBleManager.deviceModel!);
        }
      } catch (e) {}
    }
    super.onClose();
  }

  void startUpdate() async {
    
    otaOrFallback = 0;
    bool canUpdate = false;
    if (dfuModel.value?.updateInfo != null &&
        dfuModel.value?.deviceInfo.firmwareRevision !=
            dfuModel.value?.updateInfo?.version) {
      canUpdate = true;
    }
    if (isDoubleSlide) {
      if (dfuModelRight.value?.updateInfo != null &&
          dfuModelRight.value?.deviceInfo.firmwareRevision !=
              dfuModel.value?.updateInfo?.version) {
        canUpdate = true;
      }
    }
    if (canUpdate) {
      if (await bleManager.ensureDeviceConnected()) {
        // 新版本直接升级
        printError(
            info:
                "bleManager.deviceModel?.hardware:${bleManager.deviceModel?.hardware}");
        if (bleManager.deviceModel?.hardware
                    ?.startsWith(HardwareVersion.AXO_2_0.value) ==
                true ||
            bleManager.deviceModel?.hardware
                    ?.startsWith(HardwareVersion.DLS_1_0.value) ==
                true) {
          _startUpdate();
        } else {
          state(DfuPageState.needCharging);
        }
      }
      // _startUpdate();
    } else {
      showToast("当前已是最新版本。".tr);
    }
  }

  void checkCharging() async {
    needAlertChargingAfterSuccess = true;
    loaderOverlay?.show(progress: "正在检查设备".tr);
    if (bleManager.isReady.value) {
      try {
        await bleManager.connectionState.stream
            .lastWhere((test) => BluetoothConnectionState.disconnected == test)
            .timeout(Duration(seconds: 3));
      } catch (e) {}
    }
    Future reconnect(BleManager manager)async{
      int reconnectCount = 2;
      bool connectedSuccess = false;
      while(!connectedSuccess && reconnectCount > 0){
        try{
          reconnectCount -= 1;
          await manager.connect(manager.deviceModel!);
          connectedSuccess = true;
        }catch(e){
          connectedSuccess = false;
          await Future.delayed(Duration(seconds: 3));
          if (reconnectCount == 0){
            rethrow;
          }
        }
      }
    }
    await Future.delayed(Duration(seconds: 1));
    try {
      if (bleManager.deviceModel?.isDoubleSlide == true ||
          rightBleManager.deviceModel?.isDoubleSlide == true) {
        if (bleManager.deviceModel != null) {
          await reconnect(bleManager);
          if (rightBleManager.deviceModel != null) {
            await reconnect(rightBleManager);
            if (!await bleManager.isCharging() &&
                !await rightBleManager.isCharging()) {
              showToast("请确认电源是否连接".tr);
            } else {
              loaderOverlay?.hide();
              if (otaOrFallback == 0) {
                _startUpdate();
              } else if (otaOrFallback == 1) {
                _startFallback();
              }
            }
          } else {
            loaderOverlay?.hide();
          }

          // state(DfuPageState.update);
        }
      } else {
        if (bleManager.deviceModel != null) {
          await reconnect(bleManager);
          if (!await bleManager.isCharging()) {
            showToast("请确认电源是否连接".tr);
          } else {
            loaderOverlay?.hide();
            if (otaOrFallback == 0) {
              _startUpdate();
            } else if (otaOrFallback == 1) {
              _startFallback();
            }

            // state(DfuPageState.update);
          }
        }
      }
    } on FlutterBluePlusException catch (e) {
      printError(info: "checkCharging:$e");
      loaderOverlay?.hide();
      Get.dialog(
          AppDialog(
              title: "连接失败，请检查".tr,
              message: "1.设备是否已转动唤醒。\n2.设备是否有电。\n3.功率计请不要在充电状态下连接APP。".tr,
              submit: "好的，我知道了！".tr),
          barrierDismissible: false);
    } catch (e) {
      printError(info: "checkCharging:$e");
      loaderOverlay?.hide();
      Get.dialog(
          AppDialog(
              title: "连接失败，请检查".tr,
              message: "其实是其他错误:${e}",
              submit: "好的，我知道了！".tr),
          barrierDismissible: false);
    }
  }

  void _startUpdate() async {
    targetFirmwareVersion(dfuModel.value?.updateInfo?.version);
    if (dfuModel.value != null &&
        dfuModel.value?.updateInfo?.version !=
            dfuModel.value?.deviceInfo.firmwareRevision) {
      await _startOTA(
          url: dfuModel.value?.updateInfo?.upgradePackage ?? '',
          manager: bleManager,
          firmwareVersion: targetFirmwareVersion.value ?? '');
    }

    if (dfuModelRight.value != null &&
        dfuModelRight.value?.updateInfo?.version !=
            dfuModelRight.value?.deviceInfo.firmwareRevision) {
      targetFirmwareVersionRight(dfuModelRight.value?.updateInfo?.version);
      await _startOTA(
          url: dfuModelRight.value?.updateInfo?.upgradePackage ?? '',
          manager: rightBleManager!,
          firmwareVersion: targetFirmwareVersionRight.value ?? '');
    }

    if (needAlertChargingAfterSuccess) {
      await Get.dialog(
          AppDialog(
              title: "提示".tr, message: "升级成功，请及时断开充电线".tr, submit: "确定".tr),
          barrierDismissible: false);
    }
    state(DfuPageState.success);
  }

  void startFallback() async {
    try {
      loaderOverlay?.show();
      otaOrFallback = 1;
      var canFallback = false;
      String? url = "";
      if (bleManager.deviceModel != null &&
          await bleManager.ensureDeviceConnected()) {
        final pair =
            await bleManager.deviceModel?.fetchFallbackVersion(bleManager);
        fallbackPair = pair;
        url = pair?.second;
        if (url != null && url.isNotEmpty == true) {
          canFallback = true;
        }
      }

      if (rightBleManager.deviceModel != null &&
          (await rightBleManager.ensureDeviceConnected()) == true) {
        final pair = await rightBleManager.deviceModel
            ?.fetchFallbackVersion(rightBleManager);
        fallbackPairRight = pair;
        url = pair?.second;
        if (url != null && url.isNotEmpty == true) {
          canFallback = true;
        }
      }

      if (canFallback) {
        if (bleManager.deviceModel?.hardware
                    ?.startsWith(HardwareVersion.AXO_2_0.value) ==
                true ||
            bleManager.deviceModel?.hardware
                    ?.startsWith(HardwareVersion.DLS_1_0.value) ==
                true) {
          _startFallback();
        } else {
          state(DfuPageState.needCharging);
        }
        loaderOverlay?.hide();
      } else {
        showToast("无回退版本".tr);
      }
      print("canFallback:$canFallback");
    } on EmptyWriteCharacteristicError catch (e) {
      loaderOverlay?.hide();
      showToast("请先移除充电线并重新连接".tr);
    } catch (e) {
      printError(info: "fallback:$e");
      loaderOverlay?.hide();
    }
  }

  void _startFallback() async {
    targetFirmwareVersion(fallbackPair?.first);
    if (bleManager.deviceModel != null && fallbackPair != null) {
      await _startOTA(
          url: fallbackPair?.second ?? '',
          manager: bleManager,
          firmwareVersion: fallbackPair?.first ?? '');
    }
    if (rightBleManager.deviceModel != null && fallbackPairRight != null) {
      targetFirmwareVersionRight(fallbackPairRight?.first);
      await _startOTA(
          url: fallbackPairRight?.second ?? '',
          manager: rightBleManager,
          firmwareVersion: fallbackPairRight?.first ?? '');
    }
    if (needAlertChargingAfterSuccess) {
      await Get.dialog(
          AppDialog(
              title: "提示".tr, message: "升级成功，请及时断开充电线".tr, submit: "确定".tr),
          barrierDismissible: false);
    }
    state(DfuPageState.success);
  }

  Future _startOTA(
      {required String url,
      required BleManager manager,
      required String firmwareVersion}) async {
    state(DfuPageState.update);
    dfuTaskName("固件下载中...".tr);
    final dir = await getApplicationCacheDirectory();
    final savePath = path.join(dir.path, "${firmwareVersion}.zip");
    if (File(savePath).existsSync()) {
      File(savePath).deleteSync();
    }
    try {
      DateTime startDateTime = DateTime.timestamp();
      manager.dfuMode = true;
      await apiService.downloadDio.download(url, savePath,
          onReceiveProgress: (int count, int total) {
        // progress("${(count / total * 100).toStringAsFixed(1)}%");
      });
      DateTime endDateTime = DateTime.timestamp();
      final duration = endDateTime.difference(startDateTime);
      await Future.delayed(Duration(milliseconds: 2000 - duration.inMilliseconds));
      progress("");
      dfuTaskName("等待更新".tr);
      await NordicDfu().startDfu(
        '${manager.deviceModel?.address}',
        savePath,
        fileInAsset: false,
        forceDfu: false,
        androidSpecialParameter: AndroidSpecialParameter(
          disableNotification: true,
          keepBond: false,
          packetReceiptNotificationsEnabled: false,
          startAsForegroundService: false,
        ),
        name: manager.device?.platformName,
        enableUnsafeExperimentalButtonlessServiceInSecureDfu: true,
        onDfuProcessStarted: (value) {
          dfuTaskName("${manager.deviceModel?.name} ${'更新中...'.tr}");
        },
        onProgressChanged: (
          deviceAddress,
          percent,
          speed,
          avgSpeed,
          currentPart,
          partsTotal,
        ) {
          print('deviceAddress: $deviceAddress, percent: $percent');
          progress("${percent}%");
        },
      );
    } on DioException catch (e) {
      await Get.dialog(
          AppDialog(
              title: "提示".tr,
              message: "下载失败,请检查网络是否稳定！".tr,
              submit: "好的，我知道了!".tr),
          barrierDismissible: false);
      state(DfuPageState.normal);
    } on PlatformException catch (e) {
      printError(info: "$e");
      if (e.code == "4102") {
        await Get.dialog(
            AppDialog(
                title: "提示".tr, message: "更新失败,请确认电源是否连接".tr, submit: "确定".tr),
            barrierDismissible: false);
        Get.back();
      } else {
        await Get.dialog(
            AppDialog(title: "提示".tr, message: "无法进行OTA升级".tr, submit: "确定".tr),
            barrierDismissible: false);
        Get.back();
      }
    } finally {
      manager.dfuMode = false;
    }
  }
}
